Use GtkMenuTracker for Quartz backend.
authorWilliam Hua <william@attente.ca>
Wed, 8 Jan 2014 22:27:43 +0000 (17:27 -0500)
committerRyan Lortie <desrt@desrt.ca>
Wed, 8 Jan 2014 23:16:05 +0000 (18:16 -0500)
https://bugzilla.gnome.org/show_bug.cgi?id=710351

gtk/Makefile.am
gtk/gtkapplication-quartz-menu.c [new file with mode: 0644]
gtk/gtkapplication-quartz.c
gtk/gtkapplicationprivate.h
gtk/gtkmodelmenu-quartz.c [deleted file]
gtk/gtkmodelmenu-quartz.h [deleted file]

index 9a33f2867da624e7a6df218186530fb4e72f9789..6e71fbade6573f954db59b3986f1bc8b70d2f311 100644 (file)
@@ -966,8 +966,8 @@ gtk_use_win32_c_sources =   \
 gtk_use_quartz_c_sources =     \
        gtksearchenginequartz.c \
        gtkmountoperation-stub.c \
-       gtkmodelmenu-quartz.c \
        gtkapplication-quartz.c \
+       gtkapplication-quartz-menu.c \
        gtkquartz.c
 gtk_use_stub_c_sources =       \
        gtkmountoperation-stub.c
@@ -1005,7 +1005,6 @@ endif
 
 gtk_use_quartz_private_h_sources =     \
        gtksearchenginequartz.h \
-       gtkmodelmenu-quartz.h \
        gtkquartz.h
 if USE_QUARTZ
 gtk_c_sources += $(gtk_use_quartz_c_sources)
diff --git a/gtk/gtkapplication-quartz-menu.c b/gtk/gtkapplication-quartz-menu.c
new file mode 100644 (file)
index 0000000..0e00ba5
--- /dev/null
@@ -0,0 +1,377 @@
+/*
+ * Copyright © 2011 William Hua, Ryan Lortie
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: William Hua <william@attente.ca>
+ *         Ryan Lortie <desrt@desrt.ca>
+ */
+
+#include "config.h"
+
+#include "gtkapplicationprivate.h"
+#include "gtkmenutracker.h"
+#include "gtkicontheme.h"
+#include "gtktoolbar.h"
+#include "gtkquartz.h"
+
+#include <gdk/quartz/gdkquartz.h>
+
+#import <Cocoa/Cocoa.h>
+
+#define ICON_SIZE 16
+
+#define BLACK               "#000000"
+#define TANGO_CHAMELEON_3   "#4e9a06"
+#define TANGO_ORANGE_2      "#f57900"
+#define TANGO_SCARLET_RED_2 "#cc0000"
+
+@interface GNSMenu : NSMenu
+{
+  GtkMenuTracker *tracker;
+}
+
+- (id)initWithTitle:(NSString *)title model:(GMenuModel *)model observable:(GtkActionObservable *)observable;
+
+- (id)initWithTitle:(NSString *)title trackerItem:(GtkMenuTrackerItem *)trackerItem;
+
+@end
+
+@interface NSMenuItem (GtkMenuTrackerItem)
+
++ (id)menuItemForTrackerItem:(GtkMenuTrackerItem *)trackerItem;
+
+@end
+
+@interface GNSMenuItem : NSMenuItem
+{
+  GtkMenuTrackerItem *trackerItem;
+  gulong trackerItemChangedHandler;
+  GCancellable *cancellable;
+}
+
+- (id)initWithTrackerItem:(GtkMenuTrackerItem *)aTrackerItem;
+
+- (void)didChangeLabel;
+- (void)didChangeIcon;
+- (void)didChangeSensitive;
+- (void)didChangeVisible;
+- (void)didChangeToggled;
+- (void)didChangeAccel;
+
+- (void)didSelectItem:(id)sender;
+
+@end
+
+static void
+tracker_item_changed (GObject    *object,
+                      GParamSpec *pspec,
+                      gpointer    user_data)
+{
+  GNSMenuItem *item = user_data;
+  const gchar *name = g_param_spec_get_name (pspec);
+
+  if (name != NULL)
+    {
+      if (g_str_equal (name, "label"))
+        [item didChangeLabel];
+      else if (g_str_equal (name, "icon"))
+        [item didChangeIcon];
+      else if (g_str_equal (name, "visible"))
+        [item didChangeVisible];
+      else if (g_str_equal (name, "toggled"))
+        [item didChangeToggled];
+      else if (g_str_equal (name, "accel"))
+        [item didChangeAccel];
+    }
+}
+
+static void
+icon_loaded (GObject      *object,
+             GAsyncResult *result,
+             gpointer      user_data)
+{
+  GtkIconInfo *info = GTK_ICON_INFO (object);
+  GNSMenuItem *item = user_data;
+  GError *error = NULL;
+  GdkPixbuf *pixbuf;
+
+  pixbuf = gtk_icon_info_load_symbolic_finish (info, result, NULL, &error);
+
+  if (pixbuf != NULL)
+    {
+      [item setImage:_gtk_quartz_create_image_from_pixbuf (pixbuf)];
+      g_object_unref (pixbuf);
+    }
+  else
+    {
+      /* on failure to load, clear the old icon */
+      if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+        [item setImage:nil];
+
+      g_error_free (error);
+    }
+}
+
+@implementation GNSMenuItem
+
+- (id)initWithTrackerItem:(GtkMenuTrackerItem *)aTrackerItem
+{
+  self = [super initWithTitle:@""
+                       action:@selector(didSelectItem:)
+                keyEquivalent:@""];
+
+  if (self != nil)
+    {
+      [self setTarget:self];
+
+      trackerItem = g_object_ref (aTrackerItem);
+      trackerItemChangedHandler = g_signal_connect (trackerItem, "notify", G_CALLBACK (tracker_item_changed), self);
+
+      [self didChangeLabel];
+      [self didChangeIcon];
+      [self didChangeSensitive];
+      [self didChangeVisible];
+      [self didChangeToggled];
+      [self didChangeAccel];
+
+      if (gtk_menu_tracker_item_get_has_submenu (trackerItem))
+        [self setSubmenu:[[[GNSMenu alloc] initWithTitle:[self title] trackerItem:trackerItem] autorelease]];
+    }
+
+  return self;
+}
+
+- (void)dealloc
+{
+  if (cancellable != NULL)
+    {
+      g_cancellable_cancel (cancellable);
+      g_clear_object (&cancellable);
+    }
+
+  g_signal_handler_disconnect (trackerItem, trackerItemChangedHandler);
+  g_object_unref (trackerItem);
+
+  [super dealloc];
+}
+
+- (void)didChangeLabel
+{
+  gchar *label = _gtk_toolbar_elide_underscores (gtk_menu_tracker_item_get_label (trackerItem));
+
+  [self setTitle:[NSString stringWithUTF8String:label ? : ""]];
+
+  g_free (label);
+}
+
+- (void)didChangeIcon
+{
+  GIcon *icon = gtk_menu_tracker_item_get_icon (trackerItem);
+
+  if (cancellable != NULL)
+    {
+      g_cancellable_cancel (cancellable);
+      g_clear_object (&cancellable);
+    }
+
+  if (icon != NULL)
+    {
+      static gboolean parsed;
+
+      static GdkRGBA foreground;
+      static GdkRGBA success;
+      static GdkRGBA warning;
+      static GdkRGBA error;
+
+      GtkIconTheme *theme;
+      GtkIconInfo *info;
+      gint scale;
+
+      if (!parsed)
+        {
+          gdk_rgba_parse (&foreground, BLACK);
+          gdk_rgba_parse (&success, TANGO_CHAMELEON_3);
+          gdk_rgba_parse (&warning, TANGO_ORANGE_2);
+          gdk_rgba_parse (&error, TANGO_SCARLET_RED_2);
+
+          parsed = TRUE;
+        }
+
+      theme = gtk_icon_theme_get_default ();
+      scale = roundf ([[NSScreen mainScreen] backingScaleFactor]);
+      info = gtk_icon_theme_lookup_by_gicon_for_scale (theme, icon, ICON_SIZE, scale, GTK_ICON_LOOKUP_USE_BUILTIN);
+
+      if (info != NULL)
+        {
+          cancellable = g_cancellable_new ();
+          gtk_icon_info_load_symbolic_async (info, &foreground, &success, &warning, &error,
+                                             cancellable, icon_loaded, self);
+          g_object_unref (info);
+          return;
+        }
+    }
+
+  [self setImage:nil];
+}
+
+- (void)didChangeSensitive
+{
+  [self setEnabled:gtk_menu_tracker_item_get_sensitive (trackerItem) ? YES : NO];
+}
+
+- (void)didChangeVisible
+{
+  [self setHidden:gtk_menu_tracker_item_get_visible (trackerItem) ? NO : YES];
+}
+
+- (void)didChangeToggled
+{
+  [self setState:gtk_menu_tracker_item_get_toggled (trackerItem) ? NSOnState : NSOffState];
+}
+
+- (void)didChangeAccel
+{
+  const gchar *accel = gtk_menu_tracker_item_get_accel (trackerItem);
+
+  if (accel != NULL)
+    {
+      guint key;
+      GdkModifierType mask;
+      unichar character;
+      NSUInteger modifiers;
+
+      gtk_accelerator_parse (accel, &key, &mask);
+
+      character = gdk_quartz_get_key_equivalent (key);
+      [self setKeyEquivalent:[NSString stringWithCharacters:&character length:1]];
+
+      modifiers = 0;
+      if (mask & GDK_SHIFT_MASK)
+        modifiers |= NSShiftKeyMask;
+      if (mask & GDK_CONTROL_MASK)
+        modifiers |= NSControlKeyMask;
+      if (mask & GDK_MOD1_MASK)
+        modifiers |= NSAlternateKeyMask;
+      if (mask & GDK_META_MASK)
+        modifiers |= NSCommandKeyMask;
+      [self setKeyEquivalentModifierMask:modifiers];
+    }
+  else
+    {
+      [self setKeyEquivalent:@""];
+      [self setKeyEquivalentModifierMask:0];
+    }
+}
+
+- (void)didSelectItem:(id)sender
+{
+  gtk_menu_tracker_item_activated (trackerItem);
+}
+
+@end
+
+@implementation NSMenuItem (GtkMenuTrackerItem)
+
++ (id)menuItemForTrackerItem:(GtkMenuTrackerItem *)trackerItem
+{
+  if (gtk_menu_tracker_item_get_is_separator (trackerItem))
+    return [NSMenuItem separatorItem];
+
+  return [[[GNSMenuItem alloc] initWithTrackerItem:trackerItem] autorelease];
+}
+
+@end
+
+static void
+menu_item_inserted (GtkMenuTrackerItem *item,
+                    gint                position,
+                    gpointer            user_data)
+{
+  GNSMenu *menu = user_data;
+
+  [menu insertItem:[NSMenuItem menuItemForTrackerItem:item] atIndex:position];
+}
+
+static void
+menu_item_removed (gint     position,
+                   gpointer user_data)
+{
+  GNSMenu *menu = user_data;
+
+  [menu removeItemAtIndex:position];
+}
+
+@implementation GNSMenu
+
+- (id)initWithTitle:(NSString *)title model:(GMenuModel *)model observable:(GtkActionObservable *)observable
+{
+  self = [super initWithTitle:title];
+
+  if (self != nil)
+    {
+      [self setAutoenablesItems:NO];
+
+      tracker = gtk_menu_tracker_new (observable,
+                                      model,
+                                      NO,
+                                      NULL,
+                                      menu_item_inserted,
+                                      menu_item_removed,
+                                      self);
+    }
+
+  return self;
+}
+
+- (id)initWithTitle:(NSString *)title trackerItem:(GtkMenuTrackerItem *)trackerItem
+{
+  self = [super initWithTitle:title];
+
+  if (self != nil)
+    {
+      [self setAutoenablesItems:NO];
+
+      tracker = gtk_menu_tracker_new_for_item_submenu (trackerItem,
+                                                       menu_item_inserted,
+                                                       menu_item_removed,
+                                                       self);
+    }
+
+  return self;
+}
+
+- (void)dealloc
+{
+  gtk_menu_tracker_free (tracker);
+
+  [super dealloc];
+}
+
+@end
+
+void
+gtk_application_impl_quartz_setup_menu (GMenuModel     *model,
+                                        GtkActionMuxer *muxer)
+{
+  NSMenu *menu;
+
+  if (model != NULL)
+    menu = [[GNSMenu alloc] initWithTitle:@"Main Menu" model:model observable:GTK_ACTION_OBSERVABLE (muxer)];
+  else
+    menu = [[NSMenu alloc] init];
+
+  [NSApp setMainMenu:menu];
+  [menu release];
+}
index 9d9f89707aa0a7a2f2fcb778a2f45e4ed9bcc307..4527f62ece3d6f7239070c37ba260795a51bf651 100644 (file)
@@ -21,7 +21,6 @@
 #include "config.h"
 
 #include "gtkapplicationprivate.h"
-#include "gtkmodelmenu-quartz.h"
 #import <Cocoa/Cocoa.h>
 
 typedef struct
@@ -46,6 +45,9 @@ typedef struct
 {
   GtkApplicationImpl impl;
 
+  GtkActionMuxer *muxer;
+  GMenu *combined;
+
   GSList *inhibitors;
   gint quit_inhibit;
   guint next_cookie;
@@ -83,20 +85,6 @@ G_DEFINE_TYPE (GtkApplicationImplQuartz, gtk_application_impl_quartz, GTK_TYPE_A
 }
 @end
 
-static void
-gtk_application_impl_quartz_menu_changed (GtkApplicationImplQuartz *quartz)
-{
-  GMenu *combined;
-
-  combined = g_menu_new ();
-  g_menu_append_submenu (combined, "Application", gtk_application_get_app_menu (quartz->impl.application));
-  g_menu_append_section (combined, NULL, gtk_application_get_menubar (quartz->impl.application));
-
-  gtk_quartz_set_main_menu (G_MENU_MODEL (combined), quartz->impl.application);
-
-  g_object_unref (combined);
-}
-
 static void
 gtk_application_impl_quartz_startup (GtkApplicationImpl *impl,
                                      gboolean            register_session)
@@ -109,7 +97,17 @@ gtk_application_impl_quartz_startup (GtkApplicationImpl *impl,
       [NSApp setDelegate: quartz->delegate];
     }
 
-  gtk_application_impl_quartz_menu_changed (quartz);
+  quartz->muxer = gtk_action_muxer_new ();
+  gtk_action_muxer_set_parent (quartz->muxer, gtk_application_get_action_muxer (impl->application));
+
+  /* app menu must come first so that we always see index '0' in
+   * 'combined' as being the app menu.
+   */
+  gtk_application_impl_set_app_menu (impl, gtk_application_get_app_menu (impl->application));
+  gtk_application_impl_set_menubar (impl, gtk_application_get_menubar (impl->application));
+
+  /* OK.  Now put it in the menu. */
+  gtk_application_impl_quartz_setup_menu (G_MENU_MODEL (quartz->combined), quartz->muxer);
 
   [NSApp finishLaunching];
 }
@@ -119,7 +117,8 @@ gtk_application_impl_quartz_shutdown (GtkApplicationImpl *impl)
 {
   GtkApplicationImplQuartz *quartz = (GtkApplicationImplQuartz *) impl;
 
-  gtk_quartz_clear_main_menu ();
+  /* destroy our custom menubar */
+  [NSApp setMainMenu:[[[NSMenu alloc] init] autorelease]];
 
   if (quartz->delegate)
     {
@@ -131,13 +130,39 @@ gtk_application_impl_quartz_shutdown (GtkApplicationImpl *impl)
   quartz->inhibitors = NULL;
 }
 
+static void
+gtk_application_impl_quartz_active_window_changed (GtkApplicationImpl *impl,
+                                                   GtkWindow          *window)
+{
+  GtkApplicationImplQuartz *quartz = (GtkApplicationImplQuartz *) impl;
+
+  gtk_action_muxer_remove (quartz->muxer, "win");
+
+  if (G_IS_ACTION_GROUP (window))
+    gtk_action_muxer_insert (quartz->muxer, "win", G_ACTION_GROUP (window));
+}
+
 static void
 gtk_application_impl_quartz_set_app_menu (GtkApplicationImpl *impl,
                                           GMenuModel         *app_menu)
 {
   GtkApplicationImplQuartz *quartz = (GtkApplicationImplQuartz *) impl;
 
-  gtk_application_impl_quartz_menu_changed (quartz);
+  /* If there are any items at all, then the first one is the app menu */
+  if (g_menu_model_get_n_items (G_MENU_MODEL (quartz->combined)))
+    g_menu_remove (quartz->combined, 0);
+
+  if (app_menu)
+    g_menu_prepend_submenu (quartz->combined, "Application", app_menu);
+  else
+    {
+      GMenu *empty;
+
+      /* We must preserve the rule that index 0 is the app menu */
+      empty = g_menu_new ();
+      g_menu_prepend_submenu (quartz->combined, "Application", G_MENU_MODEL (empty));
+      g_object_unref (empty);
+    }
 }
 
 static void
@@ -146,7 +171,12 @@ gtk_application_impl_quartz_set_menubar (GtkApplicationImpl *impl,
 {
   GtkApplicationImplQuartz *quartz = (GtkApplicationImplQuartz *) impl;
 
-  gtk_application_impl_quartz_menu_changed (quartz);
+  /* If we have the menubar, it is a section at index '1' */
+  if (g_menu_model_get_n_items (G_MENU_MODEL (quartz->combined)) > 1)
+    g_menu_remove (quartz->combined, 1);
+
+  if (menubar)
+    g_menu_append_section (quartz->combined, NULL, menubar);
 }
 
 static guint
@@ -211,6 +241,7 @@ gtk_application_impl_quartz_is_inhibited (GtkApplicationImpl         *impl,
 static void
 gtk_application_impl_quartz_init (GtkApplicationImplQuartz *quartz)
 {
+  quartz->combined = g_menu_new ();
 }
 
 static void
@@ -218,7 +249,7 @@ gtk_application_impl_quartz_finalize (GObject *object)
 {
   GtkApplicationImplQuartz *quartz = (GtkApplicationImplQuartz *) object;
 
-  g_slist_free_full (quartz->inhibitors, (GDestroyNotify) gtk_application_quartz_inhibitor_free);
+  g_clear_object (&quartz->combined);
 
   G_OBJECT_CLASS (gtk_application_impl_quartz_parent_class)->finalize (object);
 }
@@ -230,6 +261,7 @@ gtk_application_impl_quartz_class_init (GtkApplicationImplClass *class)
 
   class->startup = gtk_application_impl_quartz_startup;
   class->shutdown = gtk_application_impl_quartz_shutdown;
+  class->active_window_changed = gtk_application_impl_quartz_active_window_changed;
   class->set_app_menu = gtk_application_impl_quartz_set_app_menu;
   class->set_menubar = gtk_application_impl_quartz_set_menubar;
   class->inhibit = gtk_application_impl_quartz_inhibit;
index db2fa0086c17a15f91e1f80698fe68b6035cd610..7847fcfb22ce77e17a1ca03cc89d09b3a2e598d0 100644 (file)
@@ -208,4 +208,8 @@ G_GNUC_INTERNAL
 gchar *                 gtk_application_impl_dbus_get_window_path       (GtkApplicationImplDBus      *dbus,
                                                                          GtkWindow                   *window);
 
+G_GNUC_INTERNAL
+void                    gtk_application_impl_quartz_setup_menu          (GMenuModel                  *model,
+                                                                         GtkActionMuxer              *muxer);
+
 #endif /* __GTK_APPLICATION_PRIVATE_H__ */
diff --git a/gtk/gtkmodelmenu-quartz.c b/gtk/gtkmodelmenu-quartz.c
deleted file mode 100644 (file)
index b099831..0000000
+++ /dev/null
@@ -1,372 +0,0 @@
-/*
- * Copyright © 2011 William Hua, Ryan Lortie
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the licence, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- *
- * Author: William Hua <william@attente.ca>
- *         Ryan Lortie <desrt@desrt.ca>
- */
-
-#include "gtkmodelmenu-quartz.h"
-
-#include <gdk/gdkkeysyms.h>
-#include "gtkaccelmapprivate.h"
-#include "gtkactionhelper.h"
-#include "../gdk/quartz/gdkquartz.h"
-
-#import <Cocoa/Cocoa.h>
-
-
-
-@interface GNSMenu : NSMenu
-{
-  GtkApplication *application;
-  GMenuModel     *model;
-  guint           update_idle;
-  GSList         *connected;
-  gboolean        with_separators;
-}
-
-- (id)initWithTitle:(NSString *)title model:(GMenuModel *)aModel application:(GtkApplication *)application hasSeparators:(BOOL)hasSeparators;
-
-- (void)model:(GMenuModel *)model didChangeAtPosition:(NSInteger)position removed:(NSInteger)removed added:(NSInteger)added;
-
-- (gboolean)handleChanges;
-
-@end
-
-
-
-@interface GNSMenuItem : NSMenuItem
-{
-  GtkActionHelper *helper;
-}
-
-- (id)initWithModel:(GMenuModel *)model index:(NSInteger)index application:(GtkApplication *)application;
-
-- (void)didSelectItem:(id)sender;
-
-- (void)helperChanged;
-
-@end
-
-
-
-static gboolean
-gtk_quartz_model_menu_handle_changes (gpointer user_data)
-{
-  GNSMenu *menu = user_data;
-
-  return [menu handleChanges];
-}
-
-static void
-gtk_quartz_model_menu_items_changed (GMenuModel *model,
-                               gint        position,
-                               gint        removed,
-                               gint        added,
-                               gpointer    user_data)
-{
-  GNSMenu *menu = user_data;
-
-  [menu model:model didChangeAtPosition:position removed:removed added:added];
-}
-
-void
-gtk_quartz_set_main_menu (GMenuModel     *model,
-                          GtkApplication *application)
-{
-  [NSApp setMainMenu:[[[GNSMenu alloc] initWithTitle:@"Main Menu" model:model application:application hasSeparators:NO] autorelease]];
-}
-
-void
-gtk_quartz_clear_main_menu (void)
-{
-  // ensure that we drop all GNSMenuItem (to ensure 'application' has no extra references)
-  [NSApp setMainMenu:[[[NSMenu alloc] init] autorelease]];
-}
-
-@interface GNSMenu ()
-
-- (void)appendFromModel:(GMenuModel *)aModel withSeparators:(BOOL)withSeparators;
-
-@end
-
-
-
-@implementation GNSMenu
-
-- (void)model:(GMenuModel *)model didChangeAtPosition:(NSInteger)position removed:(NSInteger)removed added:(NSInteger)added
-{
-  if (update_idle == 0)
-    update_idle = gdk_threads_add_idle (gtk_quartz_model_menu_handle_changes, self);
-}
-
-- (void)appendItemFromModel:(GMenuModel *)aModel atIndex:(gint)index withHeading:(gchar **)heading
-{
-  GMenuModel *section;
-
-  if ((section = g_menu_model_get_item_link (aModel, index, G_MENU_LINK_SECTION)))
-    {
-      g_menu_model_get_item_attribute (aModel, index, G_MENU_ATTRIBUTE_LABEL, "s", heading);
-      [self appendFromModel:section withSeparators:NO];
-      g_object_unref (section);
-    }
-  else
-    [self addItem:[[[GNSMenuItem alloc] initWithModel:aModel index:index application:application] autorelease]];
-}
-
-- (void)appendFromModel:(GMenuModel *)aModel withSeparators:(BOOL)withSeparators
-{
-  gint n, i;
-
-  g_signal_connect (aModel, "items-changed", G_CALLBACK (gtk_quartz_model_menu_items_changed), self);
-  connected = g_slist_prepend (connected, g_object_ref (aModel));
-
-  n = g_menu_model_get_n_items (aModel);
-
-  for (i = 0; i < n; i++)
-    {
-      NSInteger ourPosition = [self numberOfItems];
-      gchar *heading = NULL;
-
-      [self appendItemFromModel:aModel atIndex:i withHeading:&heading];
-
-      if (withSeparators && ourPosition < [self numberOfItems])
-        {
-          NSMenuItem *separator = nil;
-
-          if (heading)
-            {
-              separator = [[[NSMenuItem alloc] initWithTitle:[NSString stringWithUTF8String:heading] action:NULL keyEquivalent:@""] autorelease];
-
-              [separator setEnabled:NO];
-            }
-          else if (ourPosition > 0)
-            separator = [NSMenuItem separatorItem];
-
-          if (separator != nil)
-            [self insertItem:separator atIndex:ourPosition];
-        }
-
-      g_free (heading);
-    }
-}
-
-- (void)populate
-{
-  /* removeAllItems is available only in 10.6 and later, but it's more
-     efficient than iterating over the array of
-     NSMenuItems. performSelector: suppresses a compiler warning when
-     building on earlier OSX versions. */
-  if ([self respondsToSelector: @selector (removeAllItems)])
-    [self performSelector: @selector (removeAllItems)];
-  else
-    {
-      /* Iterate from the bottom up to save reindexing the NSArray. */
-      int i;
-      for (i = [self numberOfItems]; i > 0; i--)
-       [self removeItemAtIndex: i];
-    }
-
-  [self appendFromModel:model withSeparators:with_separators];
-}
-
-- (gboolean)handleChanges
-{
-  while (connected)
-    {
-      g_signal_handlers_disconnect_by_func (connected->data, gtk_quartz_model_menu_items_changed, self);
-      g_object_unref (connected->data);
-
-      connected = g_slist_delete_link (connected, connected);
-    }
-
-  [self populate];
-
-  update_idle = 0;
-
-  return G_SOURCE_REMOVE;
-}
-
-- (id)initWithTitle:(NSString *)title model:(GMenuModel *)aModel application:(GtkApplication *)anApplication hasSeparators:(BOOL)hasSeparators
-{
-  if((self = [super initWithTitle:title]) != nil)
-    {
-      [self setAutoenablesItems:NO];
-
-      model = g_object_ref (aModel);
-      application = g_object_ref (anApplication);
-      with_separators = hasSeparators;
-
-      [self populate];
-    }
-
-  return self;
-}
-
-- (void)dealloc
-{
-  while (connected)
-    {
-      g_signal_handlers_disconnect_by_func (connected->data, gtk_quartz_model_menu_items_changed, self);
-      g_object_unref (connected->data);
-
-      connected = g_slist_delete_link (connected, connected);
-    }
-
-  g_object_unref (application);
-  g_object_unref (model);
-
-  [super dealloc];
-}
-
-@end
-
-
-
-static void
-gtk_quartz_action_helper_changed (GObject    *object,
-                                  GParamSpec *pspec,
-                                  gpointer    user_data)
-{
-  GNSMenuItem *item = user_data;
-
-  [item helperChanged];
-}
-
-@implementation GNSMenuItem
-
-- (id)initWithModel:(GMenuModel *)model index:(NSInteger)index application:(GtkApplication *)application
-{
-  gchar *title = NULL;
-
-  if (g_menu_model_get_item_attribute (model, index, G_MENU_ATTRIBUTE_LABEL, "s", &title))
-    {
-      gchar *from, *to;
-
-      to = from = title;
-
-      while (*from)
-        {
-          if (*from == '_' && from[1])
-            from++;
-
-          *to++ = *from++;
-        }
-
-      *to = '\0';
-    }
-
-  if ((self = [super initWithTitle:[NSString stringWithUTF8String:title ? : ""] action:@selector(didSelectItem:) keyEquivalent:@""]) != nil)
-    {
-      GMenuModel *submenu;
-      gchar      *action;
-      GVariant   *target;
-
-      action = NULL;
-      g_menu_model_get_item_attribute (model, index, G_MENU_ATTRIBUTE_ACTION, "s", &action);
-      target = g_menu_model_get_item_attribute_value (model, index, G_MENU_ATTRIBUTE_TARGET, NULL);
-
-      if ((submenu = g_menu_model_get_item_link (model, index, G_MENU_LINK_SUBMENU)))
-        {
-          [self setSubmenu:[[[GNSMenu alloc] initWithTitle:[NSString stringWithUTF8String:title] model:submenu application:application hasSeparators:YES] autorelease]];
-          g_object_unref (submenu);
-        }
-
-      else if (action != NULL)
-        {
-          GtkAccelKey key;
-          gchar *path;
-
-          helper = gtk_action_helper_new_with_application (application);
-          gtk_action_helper_set_action_name         (helper, action);
-          gtk_action_helper_set_action_target_value (helper, target);
-
-          g_signal_connect (helper, "notify", G_CALLBACK (gtk_quartz_action_helper_changed), self);
-
-          [self helperChanged];
-
-          path = _gtk_accel_path_for_action (action, target);
-          if (gtk_accel_map_lookup_entry (path, &key))
-            {
-              unichar character = gdk_quartz_get_key_equivalent (key.accel_key);
-
-              if (character)
-                {
-                  NSUInteger modifiers = 0;
-
-                  if (key.accel_mods & GDK_SHIFT_MASK)
-                    modifiers |= NSShiftKeyMask;
-
-                  if (key.accel_mods & GDK_MOD1_MASK)
-                    modifiers |= NSAlternateKeyMask;
-
-                  if (key.accel_mods & GDK_CONTROL_MASK)
-                    modifiers |= NSControlKeyMask;
-
-                  if (key.accel_mods & GDK_META_MASK)
-                    modifiers |= NSCommandKeyMask;
-
-                  [self setKeyEquivalent:[NSString stringWithCharacters:&character length:1]];
-                  [self setKeyEquivalentModifierMask:modifiers];
-                }
-            }
-
-          g_free (path);
-
-          [self setTarget:self];
-        }
-    }
-
-  g_free (title);
-
-  return self;
-}
-
-- (void)dealloc
-{
-  if (helper != NULL)
-    g_object_unref (helper);
-
-  [super dealloc];
-}
-
-- (void)didSelectItem:(id)sender
-{
-  gtk_action_helper_activate (helper);
-}
-
-- (void)helperChanged
-{
-  [self setEnabled:gtk_action_helper_get_enabled (helper)];
-  [self setState:gtk_action_helper_get_active (helper)];
-
-  switch (gtk_action_helper_get_role (helper))
-    {
-      case GTK_ACTION_HELPER_ROLE_NORMAL:
-        [self setOnStateImage:nil];
-        break;
-      case GTK_ACTION_HELPER_ROLE_TOGGLE:
-        [self setOnStateImage:[NSImage imageNamed:@"NSMenuCheckmark"]];
-        break;
-      case GTK_ACTION_HELPER_ROLE_RADIO:
-        [self setOnStateImage:[NSImage imageNamed:@"NSMenuRadio"]];
-        break;
-      default:
-        g_assert_not_reached ();
-    }
-}
-
-@end
diff --git a/gtk/gtkmodelmenu-quartz.h b/gtk/gtkmodelmenu-quartz.h
deleted file mode 100644 (file)
index 1be9220..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright © 2011 William Hua
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the licence, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- *
- * Author: William Hua <william@attente.ca>
- */
-
-#ifndef __GTK_MODELMENU_QUARTZ_H__
-#define __GTK_MODELMENU_QUARTZ_H__
-
-#include "gtkapplication.h"
-
-void gtk_quartz_set_main_menu   (GMenuModel     *model,
-                                 GtkApplication *application);
-
-void gtk_quartz_clear_main_menu (void);
-
-#endif /* __GTK_MODELMENU_QUARTZ_H__ */